package org.xinjiang.data.migration.flush.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils;
import org.xinjiang.data.migration.flush.convert.SysUserDepartConvert;
import org.xinjiang.data.migration.flush.service.ISettingSaveService;
import org.xinjiang.data.migration.hainan.entity.*;
import org.xinjiang.data.migration.hainan.enums.KeyColumnEnum;
import org.xinjiang.data.migration.hainan.service.*;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author: 邢卫
 * @date: 2023年12月14日 19:20
 */
@Service
public class SettingSaveServiceImpl<T> implements ISettingSaveService<T> {

    @Autowired
    private ISysDepartService sysDepartService;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private IMstCommunityVolunteerService volunteerService;

    @Autowired
    private IMstCommunityWorkerService workerService;

    @Autowired
    private ICorrectionteamFunctionaryService functionaryService;

    @Autowired
    private SysUserDepartConvert sysUserDepartConvert;

    @Autowired
    private ISysUserDepartService userDepartService;

    @Override
    public Integer clearTabelData() {
        int i = 0;
        if (!sysDepartService.remove(new QueryWrapper<>())) {
            i += 1;
        }
        if (!sysUserService.clearTabelData()) {
            i += 1;
        }
        if (!volunteerService.remove(new QueryWrapper<>())) {
            i += 1;
        }
        if (!workerService.remove(new QueryWrapper<>())) {
            i += 1;
        }
        if (!functionaryService.remove(new QueryWrapper<>())) {
            i += 1;
        }
        return i;
    }

    @Override
    public Set<String> queryNotIds(KeyColumnEnum tableSysDepart) {
        IService iService = toService(tableSysDepart);
        String sourceId = tableSysDepart.getSourceId();
        QueryWrapper<T> wrapper = new QueryWrapper<>();
        wrapper.select(sourceId);
        List<T> list = iService.list(wrapper);

        Set<String> collect = list.stream().map(item -> getObject(item, sourceId).toString()).collect(Collectors.toSet());
        return collect;
    }

    @Override
    public Integer updateCreateUserDerart(Integer size) {
        int current = 1;
        boolean hasPrevious = false;
        int result = 0;
        //清楚原始数据，防止重复
        userDepartService.remove(new QueryWrapper<>());
        do {
            IPage<SysUser> page = new Page<>(current, size);
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.isNotNull(SysUser::getDepartIds);
            IPage<SysUser> iPage = sysUserService.page(page, queryWrapper);
            if (iPage instanceof Page) {
                hasPrevious = ((Page) iPage).hasNext();
            }
            current++;

            Collection<SysUserDepart> userDeparts = sysUserDepartConvert.converts(iPage.getRecords());
            boolean saveBatch = userDepartService.saveBatch(userDeparts);
            if (!saveBatch) {
                result += 1;
            }
        } while (hasPrevious);
        return result;
    }

    @Override
    public Integer updateCreateUpdateBy(Integer size) {
        int current = 1;
        boolean hasPrevious = false;
        int result = 0;
        do {
            IPage<SysUser> page = new Page<>(current, size);
            IPage<SysUser> iPage = sysUserService.page(page);
            if (iPage instanceof Page) {
                hasPrevious = ((Page) iPage).hasNext();
            }
            current++;
            List<SysUser> records = page.getRecords();
            //更新user
            result += updateUser(records);
            //社会工作者
            result += updateSocialWorker(records);
            //工作者
            result += updateWorkingPersonnel(records);
            //志愿者
            result += updateVolunteer(records);
            //部门
            result += updateDepart(records);

        } while (hasPrevious);
        return result;
    }

    /**
     * 工作人员
     *
     * @return
     */
    private Integer updateDepart(List<SysUser> sourceUser) {
        Integer result = 0;
        for (SysUser user : sourceUser) {
            LambdaUpdateWrapper<SysDepart> updateCreateByWrapper = new LambdaUpdateWrapper<>();
            updateCreateByWrapper.eq(SysDepart::getCreateBy, user.getSourceId());
            updateCreateByWrapper.set(SysDepart::getCreateBy, user.getUsername());
            boolean update = sysDepartService.update(updateCreateByWrapper);
            if (!update) {
                result += 1;
            }

            LambdaUpdateWrapper<SysDepart> updateByWrapper = new LambdaUpdateWrapper<>();
            updateByWrapper.eq(SysDepart::getUpdateBy, user.getSourceId());
            updateByWrapper.set(SysDepart::getUpdateBy, user.getUsername());
            update = sysDepartService.update(updateByWrapper);

            if (!update) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * 工作人员
     *
     * @return
     */
    private Integer updateWorkingPersonnel(List<SysUser> sourceUser) {
        Integer result = 0;
        for (SysUser user : sourceUser) {
            LambdaUpdateWrapper<CorrectionteamFunctionary> updateCreateByWrapper = new LambdaUpdateWrapper<>();
            updateCreateByWrapper.eq(CorrectionteamFunctionary::getCreateBy, user.getSourceId());
            updateCreateByWrapper.set(CorrectionteamFunctionary::getCreateBy, user.getUsername());
            boolean update = functionaryService.update(updateCreateByWrapper);
            if (!update) {
                result += 1;
            }

            LambdaUpdateWrapper<CorrectionteamFunctionary> updateByWrapper = new LambdaUpdateWrapper<>();
            updateByWrapper.eq(CorrectionteamFunctionary::getUpdateBy, user.getSourceId());
            updateByWrapper.set(CorrectionteamFunctionary::getUpdateBy, user.getUsername());
            update = functionaryService.update(updateByWrapper);
            if (!update) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * 社会工作者
     *
     * @return
     */
    private Integer updateSocialWorker(List<SysUser> sourceUser) {
        Integer result = 0;
        for (SysUser user : sourceUser) {
            LambdaUpdateWrapper<MstCommunityWorker> updateCreateByWrapper = new LambdaUpdateWrapper<>();
            updateCreateByWrapper.eq(MstCommunityWorker::getCreateBy, user.getSourceId());
            updateCreateByWrapper.set(MstCommunityWorker::getCreateBy, user.getUsername());
            boolean update = workerService.update(updateCreateByWrapper);
            if (!update) {
                result += 1;
            }

            LambdaUpdateWrapper<MstCommunityWorker> updateByWrapper = new LambdaUpdateWrapper<>();
            updateByWrapper.eq(MstCommunityWorker::getUpdateBy, user.getSourceId());
            updateByWrapper.set(MstCommunityWorker::getUpdateBy, user.getUsername());
            update = workerService.update(updateByWrapper);
            if (!update) {
                result += 1;
            }
        }
        return result;
    }

    /**
     * 志愿者
     *
     * @param sourceUser
     * @return
     */
    private Integer updateVolunteer(List<SysUser> sourceUser) {
        Integer result = 0;
        for (SysUser user : sourceUser) {
            LambdaUpdateWrapper<MstCommunityVolunteer> updateCreateByWrapper = new LambdaUpdateWrapper<>();
            updateCreateByWrapper.eq(MstCommunityVolunteer::getCreateBy, user.getSourceId());
            updateCreateByWrapper.set(MstCommunityVolunteer::getCreateBy, user.getUsername());
            boolean update = volunteerService.update(updateCreateByWrapper);
            if (!update) {
                result += 1;
            }

            LambdaUpdateWrapper<MstCommunityVolunteer> updateByWrapper = new LambdaUpdateWrapper<>();
            updateByWrapper.eq(MstCommunityVolunteer::getUpdateBy, user.getSourceId());
            updateByWrapper.set(MstCommunityVolunteer::getUpdateBy, user.getUsername());
            update = volunteerService.update(updateByWrapper);
            if (!update) {
                result += 1;
            }
        }
        return result;
    }


    /**
     * 更新user里面的创建人和更新人
     *
     * @param sourceUser
     * @return
     */
    private Integer updateUser(List<SysUser> sourceUser) {
        Integer result = 0;
        for (SysUser user : sourceUser) {
            LambdaUpdateWrapper<SysUser> updateCreateByWrapper = new LambdaUpdateWrapper<>();
            updateCreateByWrapper.eq(SysUser::getCreateBy, user.getSourceId());
            updateCreateByWrapper.set(SysUser::getCreateBy, user.getUsername());
            boolean update = sysUserService.update(updateCreateByWrapper);
            if (!update) {
                result += 1;
            }

            LambdaUpdateWrapper<SysUser> updateByWrapper = new LambdaUpdateWrapper<>();
            updateByWrapper.eq(SysUser::getUpdateBy, user.getSourceId());
            updateByWrapper.set(SysUser::getUpdateBy, user.getUsername());
            update = sysUserService.update(updateByWrapper);
            if (!update) {
                result += 1;
            }
        }
        return result;
    }

    private Object getObject(T datum, String colum) {
        String c = convertToCamelCase(colum);
        Field field = ReflectionUtils.findField(datum.getClass(), c);
        field.setAccessible(true);
        return ReflectionUtils.getField(field, datum);
    }

    private String convertToCamelCase(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母大写
            return name.toLowerCase();
        }
        // 用下划线将原始字符串分割
        String[] camels = name.split("_");
        for (String camel : camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 首字母大写
            result.append(camel.substring(0, 1).toUpperCase());
            result.append(camel.substring(1).toLowerCase());
        }
        StringBuilder ret = new StringBuilder(result.substring(0, 1).toLowerCase());
        ret.append(result.substring(1, result.toString().length()));
        return ret.toString();
    }

    private void setObject(T datum, Object value, String colum) {
        String c = convertToCamelCase(colum);
        Field field = ReflectionUtils.findField(datum.getClass(), c);
        field.setAccessible(true);
        ReflectionUtils.setField(field, datum, value);
    }

    private IService toService(KeyColumnEnum columnEnum) {
        switch (columnEnum) {
            case TABLE_SYS_DEPART:
                return sysDepartService;
            case TABLE_SYS_USER:
                return sysUserService;
            case TABLE_MST_COMMUNITY_VOLUNTEER:
                return volunteerService;
            case TABLE_MST_CORRECTIONTEAM_FUNCTIONARY:
                return functionaryService;
            case TABLE_MST_COMMUNITY_WORKER:
                return workerService;
            default:
                throw new RuntimeException("当前接口还未实现");
        }
    }

    @Override
    public Integer saveBatch(KeyColumnEnum columnEnum, Collection<T> data) {
        IService service = toService(columnEnum);
        String sourceId = columnEnum.getSourceId();
        if (StringUtils.isEmpty(sourceId)) {
            throw new RuntimeException("当前接口请传入正确的更新条件");
        }
        if (CollectionUtils.isEmpty(data)) {
            return 0;
        }
        List<T> list = queryData(data, columnEnum, service);
        Map<Object, Object> toMap = toMap(list, columnEnum);
        if (!CollectionUtils.isEmpty(toMap)) {
            for (T datum : data) {
                Object object = getObject(datum, sourceId);
                Object remove = toMap.remove(object);
                if (remove != null) {
                    setObject(datum, remove, columnEnum.getTableIdName());
                }
            }
        }
        boolean batch = service.saveOrUpdateBatch(data);
        if (batch) {
            return 0;
        }
        return data.size();
    }


    private List<T> queryData(Collection<T> data, KeyColumnEnum columnEnum, IService service) {
        String sourceId = columnEnum.getSourceId();
        List<Object> collect = data.stream().map(item -> getObject(item, sourceId)).collect(Collectors.toList());
        return queryData(service, columnEnum, collect);
    }

    private List<T> queryData(IService service, KeyColumnEnum columnEnum, Collection<Object> collect) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(columnEnum.getSourceId(), collect);
        queryWrapper.select(columnEnum.getSourceId(), columnEnum.getTableIdName());
        return service.list(queryWrapper);
    }


    @Override
    public Integer updateBatchDepartParent(KeyColumnEnum columnEnum, Collection<T> converts) {
        IService service = toService(columnEnum);
        List<T> list = queryData(converts, columnEnum, sysDepartService);
        Map<Object, Object> toMap = toMap(list, columnEnum);//数据源与本地id关系
        for (T t : converts) {
            Object object = getObject(t, columnEnum.getSourceId());
            object = toMap.remove(object);
            setObject(t, object, columnEnum.getTableIdName());
        }

        boolean batch = service.updateBatchById(converts);
        if (batch) {
            return 0;
        }
        return converts.size();
    }

    private Map<Object, Object> toMap(List<T> list, KeyColumnEnum columnEnum) {
        Map<Object, Object> data = new HashMap<>();
        if (CollectionUtils.isEmpty(list)) {
            return data;
        }
        for (T t : list) {
            Object id = getObject(t, columnEnum.getTableIdName());
            Object sourceId = getObject(t, columnEnum.getSourceId());
            data.put(sourceId, id);
        }
        return data;
    }
}
